<template>
  <div class="edit-list-wrap">
    <div class="edit-list-left">
      <div
        class="edit-item-wrap"
        v-for="(item, index) in cloneList"
        :key="index"
        :style="{ width: item.width + '%' }"
        :class="[
          { flexStart: checkFlexStatus(item) },
          { unNeed: item.isNeed === false },
        ]"
      >
        <template v-if="item.type !== 'slot'">
          <div class="edit-label" :style="{ width: widthLabel + 'px' }">
            <div class="edit-text">
              <span class="star">*</span>
              <span>{{ item.label }}</span>
            </div>
          </div>
          <div
            class="edit-item-right"
            :class="{ errorStatus: errorObj[item.id] }"
          >
            <div class="edit-error-label">{{ item.currentErrorLabel }}</div>
            <template v-if="item.type == 'input'">
              <el-input
                v-model="item.value"
                clearable
                @blur="inputBlurHandle(item)"
                :placeholder="`请输入${item.label}`"
                :maxlength="item.maxlength"
                :type="item.inputType || 'text'"
                :max="item.max"
                :min="item.min"
                :disabled="item.disabled"
                :show-password="item.showPassword"
                :autocomplete="item.autocomplete"
              ></el-input>
            </template>

            <template v-if="item.type == 'select'">
              <el-select
                v-model="item.value"
                :filterable="item.filterable"
                :multiple="item.multiple"
                :collapse-tags="item.multiple"
                clearable
                :placeholder="
                  item.placeholder ||
                  (item.multiple ? '请选择(可多选)' : `请选择`)
                "
                @change="selectChangeHandle(item)"
                :disabled="item.disabled"
              >
                <el-option
                  v-for="(citem, cindex) in item.list"
                  :key="cindex"
                  :label="
                    item.labelWord !== undefined
                      ? citem[item.labelWord]
                      : citem.label
                  "
                  :value="
                    item.valueWord !== undefined
                      ? citem[item.valueWord]
                      : citem.value
                  "
                >
                </el-option>
              </el-select>
            </template>
            <template v-if="item.type == 'treeSingle'">
              <TrTreeSelectVue
                v-model="item.value"
                :ftObj="item"
                :treeData="item.list"
                :showWord="item.showWord"
                :valueWord="item.valueWord"
                :defaultKeys="item.defaultKeys"
                :disabled="item.disabled"
                @selectBack="selectBack"
              />
            </template>
            <template v-if="item.type == 'treeMultiple'">
              <TrTreeSelectMultiple
                v-model="item.value"
                :ftObj="item"
                :treeData="item.list"
                :defExpandAll="item.defExpandAll"
                :showWord="item.showWord"
                :valueWord="item.valueWord"
                :checkStrictly="item.checkStrictly"
                :disabled="item.disabled"
                @selectBack="selectBack"
              />
            </template>
            <template v-if="item.type == 'radio'">
              <el-radio-group
                v-model="item.value"
                v-removeAriaHidden
                @change="changeRadioHandle(item)"
              >
                <el-radio
                  v-for="rItem in item.list"
                  :key="rItem.value"
                  :label="rItem.value"
                  >{{ rItem.label }}</el-radio
                >
              </el-radio-group>
            </template>
            <template v-if="item.type == 'daterange'">
              <el-date-picker
                v-model="item.value"
                type="daterange"
                range-separator="-"
                start-placeholder="开始日期"
                end-placeholder="结束日期"
                value-format="yyyy-MM-dd"
                @change="selectChangeHandle(item)"
                :disabled="item.disabled"
              >
              </el-date-picker>
            </template>
            <template v-if="item.type == 'datetimerange'">
              <el-date-picker
                v-model="item.value"
                type="datetimerange"
                range-separator="-"
                start-placeholder="开始日期"
                end-placeholder="结束日期"
                value-format="yyyy-MM-dd"
                @change="selectChangeHandle(item)"
                :disabled="item.disabled"
              >
              </el-date-picker>
            </template>
            <template v-if="item.type == 'date'">
              <el-date-picker
                v-model="item.value"
                type="date"
                placeholder="选择日期"
                value-format="yyyy-MM-dd HH:mm:ss"
                @change="selectChangeHandle(item)"
                :disabled="item.disabled"
                :picker-options="item.datePickerOptions"
              >
              </el-date-picker>
            </template>
            <template v-if="item.type == 'datetime'">
              <el-date-picker
                v-model="item.value"
                type="datetime"
                placeholder="选择日期"
                value-format="yyyy-MM-dd HH:mm:ss"
                @change="selectChangeHandle(item)"
                :disabled="item.disabled"
              >
              </el-date-picker>
            </template>
            <template v-if="item.type == 'month'">
              <el-date-picker
                v-model="item.value"
                type="month"
                placeholder="选择月"
                value-format="yyyy-MM"
                @change="selectChangeHandle(item)"
                :disabled="item.disabled"
              >
              </el-date-picker>
            </template>
            <template v-if="item.type == 'checkbox'">
              <div class="check-box">
                <div
                  class="check-item"
                  v-for="(citem, cindex) in item.list"
                  :key="citem.label"
                  @click="changeCheckHandles(citem, item, cindex)"
                >
                  <div
                    class="check-icon"
                    :class="{ active: item.value.includes(citem.value) }"
                  ></div>
                  <div class="check-label">{{ citem.label }}</div>
                </div>
              </div>
            </template>
            <template v-if="item.type == 'textarea'">
              <el-input
                type="textarea"
                @blur="inputBlurHandle(item)"
                :placeholder="`请输入${item.label}`"
                v-model="item.value"
                :maxlength="item.maxlength"
                :disabled="item.disabled"
                :show-word-limit="item.showLimit"
              >
              </el-input>
            </template>
            <template v-if="item.type == 'loadselect'">
              <TrLoadSelect
                v-model="item.value"
                :requestObj="item.requestObj"
                :ftObject="item"
                :defaultParams="item.defaultParams"
                :disabled="item.disabled !== undefined ? item.disabled : false"
                :outSelectLabel.sync="item.selectedLabel"
                :isSaveLoad="item.isSaveLoad"
                :searchPlaceholder="item.searchPlaceholder"
                @change="changeSelectHandle"
                @clear="loadClearHandle"
              />
            </template>
            <template v-if="item.type == 'upload'">
              <TrUploadList
                v-model="item.value"
                :action="item.action"
                :fileType="item.fileType"
                :multiple="item.multiple"
                :limitNum="item.limitNum"
                :uploadTip="item.uploadTip"
                :ftObject="item"
                :fileWidth="item.fileWidth"
                @upload-back="uploadBackHandle"
              />
            </template>
          </div>
        </template>
        <template v-else>
          <slot :name="item.slotName" :item="item"> </slot>
        </template>
      </div>
    </div>
    <div class="edit-list-right"></div>
  </div>
</template>

<script>
import { getObjType } from "@/utils/util";
import { cloneDeep } from "lodash-es";
import { isvalidPhone, isvalidEmail, isvalidIdCard } from "@/utils/validate";
import TrTreeSelectVue from "../Tr-tree-select/Tr-tree-select.vue";
import TrLoadSelect from "@/components/Tr-load/Tr-load.vue";
import TrTreeSelectMultiple from "../Tr-tree-select-multiple/Tr-tree-select-multiple.vue";
import TrUploadList from "../Tr-upload-list/Tr-upload-list.vue";
export default {
  components: {
    TrLoadSelect,
    TrTreeSelectVue,
    TrTreeSelectMultiple,
    TrUploadList,
  },
  props: {
    contentWidth: {
      type: Number,
      default: 960,
    },
    list: {
      type: Array,
      default: () => [],
    },
    labelWidth: {
      type: Number,
      default: 72,
    },
    formData: {
      type: Object,
      default: () => {},
    },
    value: {
      type: [Array, String, Object],
    },
    relationList: {
      type: Array,
      default: () => [],
    },
  },
  computed: {},
  watch: {
    cloneList: {
      handler(newVal, oldVal) {
        if (!this.relationList.length || this.isUpdate) return;
        this.isUpdate = true;
        const newValMap = new Map(newVal.map((item) => [item.id, item]));
        this.relationList.forEach((rItem) => {
          const { relaList: childIdList } = rItem;
          const reItem = newValMap.get(rItem.id);
          if (!reItem) return;
          const isEmptyValue =
            (Array.isArray(reItem.value) && reItem.value.length === 0) ||
            !reItem.value;

          childIdList.forEach((val) => {
            const item = newValMap.get(val.relaId);
            if (!item) return;
            if (isEmptyValue) {
              if (!val.isNotStrict) this.$set(item, "disabled", true);
              if (val.relaValue) item.value = "";
              if (val.relaLabel) item.selectedLabel = "";
              if (
                val.params &&
                val.params.length > 0 &&
                item.defaultParams !== undefined
              ) {
                val.params.forEach((k) => {
                  item.defaultParams[k.labelWord] = "";
                });
              }
            } else {
              const oldCol = this.$findByProperty(this.oldList, "id", rItem.id);
              const isOldValueEmpty =
                !oldCol ||
                (Array.isArray(oldCol.value) && oldCol.value.length === 0) ||
                !oldCol.value;
              if (isOldValueEmpty) {
                item.disabled = false;
                this.errorObj[item.id] = false;
                if (val.disabled) item.disabled = true;
                if (val.relaValue)
                  item.value = this.getEditValue(
                    reItem[val.relaValue],
                    val.reviewValue
                  );
                // if (val.relaLabel) item.selectedLabel =  reItem[val.relaLabel];
                if (val.relaLabel)
                  item.selectedLabel = this.getEditValue(
                    reItem[val.relaLabel],
                    val.reviewValue
                  );
              } else {
                if (reItem.value !== oldCol.value) {
                  if (val.relaValue) {
                    item.value = this.getEditValue(
                      reItem[val.relaValue],
                      val.reviewValue
                    );
                  } else {
                    item.value = "";
                  }
                  if (val.relaLabel) {
                    item.selectedLabel = this.getEditValue(
                      reItem[val.relaLabel],
                      val.reviewValue
                    );
                  } else {
                    item.selectedLabel = "";
                  }
                }
              }
              if (
                val.params &&
                val.params.length > 0 &&
                item.defaultParams !== undefined
              ) {
                val.params.forEach((k) => {
                  item.defaultParams[k.labelWord] = reItem[k.realWord];
                });
              }
            }
          });
        });

        this.$forceUpdate();
        this.$nextTick(() => {
          this.oldList = cloneDeep(oldVal);
          this.isUpdate = false;
        });
      },
      deep: true,
    },
  },
  data: () => ({
    oldList: [],
    cloneList: [],
    errorObj: {},
    deptDic: [],
    cloneFormData: {},
    isUpdate: false,
    defaultWordList: ["value", "label", "width", "id", "type", "list"],
    widthLabel: 72,
  }),
  methods: {
    getLabelWidth() {
      const textList = this.cloneList.filter((item) => item.type != "slot");
      if (!textList.length) return;
      const maxTextLength = textList.reduce((maxLength, obj) => {
        return Math.max(maxLength, obj.label.length);
      }, 0);
      const isNoStar = textList.every((obj) => obj.isNeed === false);
      if (maxTextLength >= 8) {
        this.widthLabel = 8 * 14 + 16;
      } else {
        this.widthLabel = maxTextLength * 14 + 16;
      }
      if (!isNoStar) this.widthLabel += 8;
    },
    loadClearHandle(val) {
      this.$emit("clear", val);
    },
    changeRadioHandle(val) {
      this.$emit("radio-change", val);
    },
    getEditValue(value, label) {
      if (value !== undefined) return value;
      let list = Object.keys(this.cloneFormData);
      if (!list.length || !label) return "";
      return this.cloneFormData[label] || "";
    },
    changeSelectHandle(val) {
      this.$emit("select-change", val);
      this.errorObj[val.ftId] = false;
      if (!this.relationList.length) return;
      let reList = this.relationList.map((item) => item.id);
      if (!reList.includes(val.ftId)) return;
      if (!val.rlValue) return;
      const rItem = this.$findByProperty(this.cloneList, "id", val.ftId);
      Object.keys(val).forEach((item) => {
        if (!this.defaultWordList.includes(item)) {
          rItem[item] = val[item];
        }
      });
    },
    selectBack(val) {
      this.errorObj[val.id] = false;
    },
    returnValue() {
      let params = {};
      let loadLabelObj = {};
      this.cloneList.forEach((item) => {
        params[item.id] = item.value;
        if (item.type == "loadselect") {
          loadLabelObj[item.id] = item.selectedLabel;
        }
        if (item.valueLabel) params[item.valueLabel] = item.selectedLabel;
      });
      this.$emit("load-label", loadLabelObj);
      this.$emit("input", params);
    },
    validator(obj, value) {
      let fItem = this.cloneList.find((item) => item.id == obj.id);
      if (fItem.isNeed === false) {
        if (
          value === "" ||
          value === undefined ||
          value === null ||
          (Array.isArray(value) && value.length == 0)
        ) {
          fItem.currentErrorLabel = "";
          this.errorObj[fItem.id] = false;
          return;
        }
      }
      if (
        value === "" ||
        value === undefined ||
        value === null ||
        (Array.isArray(value) && value.length < 1)
      ) {
        fItem.currentErrorLabel = `${fItem.label}不能为空`;
        this.$set(this.errorObj, obj.id, true);
        return;
      }
      let verFlag = false;
      if (fItem.verType !== undefined) {
        if (fItem.verType === "phone") {
          verFlag = !isvalidPhone(fItem.value);
        }
        if (fItem.verType === "email") {
          verFlag = !isvalidEmail(fItem.value);
        }

        if (fItem.verType === "idCard") {
          verFlag = !isvalidIdCard(fItem.value);
        }
        this.errorObj[fItem.id] = verFlag;
        if (verFlag) {
          fItem.currentErrorLabel = `请输入正确的${fItem.label}`;
        }
        return;
      }
      if (fItem.verRule !== undefined && typeof fItem.verRule == "function") {
        verFlag = !fItem.verRule(fItem.value);
        this.errorObj[fItem.id] = verFlag;
        if (verFlag) {
          fItem.currentErrorLabel =
            fItem.verErrorLabel !== undefined
              ? fItem.verErrorLabel
              : `请输入正确的${fItem.label}`;
        }

        return;
      }
      this.errorObj[fItem.id] = false;
    },
    validateHandle() {
      let validFlag = true;
      this.cloneList.forEach((item) => {
        this.validator(item, item.value);
      });
      for (let v in this.errorObj) {
        if (this.errorObj[v] == true) validFlag = false;
      }
      this.$forceUpdate();
      if (validFlag) {
        this.returnValue();
      }
      return validFlag;
    },
    checkFlexStatus(item) {
      return item.type == "textarea" || item.type == "upload";
    },
    inputBlurHandle(val) {
      this.validator(val, val.value);
      this.$emit("input-change", val);
      this.$nextTick(() => {
        this.$forceUpdate();
      });
    },
    selectChangeHandle(val) {
      let reObj = val;
      if (val.type == "select" && !val.multiple && val.value !== "") {
        let valueStr = val.valueWord || "value";
        const rItem = this.$findByProperty(val.list, valueStr, val.value);
        Object.keys(rItem).forEach((item) => {
          if (!this.defaultWordList.includes(item)) {
            reObj[item] = rItem[item];
          }
        });
      }
      this.$emit("select-change", reObj);
      this.errorObj[val.id] = false;
    },
    resetCloneList(id, val) {
      this.cloneList.forEach((item, index) => {
        if (item.id != id) return;
        if (getObjType(val) == "object") {
          this.$set(this.cloneList, index, val);
        } else {
          const column = this.$findByProperty(this.cloneList, "id", id);
          this.$set(column, "value", val);
        }
        this.errorObj[item.id] = false;
      });
    },
    changeCheckHandles(citem, item) {
      if (item.value.includes(citem.value)) {
        item.value = item.value.filter((val) => val != citem.value);
        return;
      }
      item.value.push(citem.value);
      this.errorObj[item.id] = false;
    },
    initHandle() {
      this.cloneList = cloneDeep(this.list);
      this.getLabelWidth();
      this.cloneList.forEach((item) => {
        this.$set(item, "currentErrorLabel", "");
        this.$set(this.errorObj, item.id, false);
      });
      if (this.formData) {
        let idsList = this.cloneList.map((item) => item.id);
        this.cloneFormData = cloneDeep(this.formData);
        let list = Object.keys(this.cloneFormData);
        if (list.length) {
          idsList.forEach((key) => {
            this.cloneList.forEach((val) => {
              if (val.id == key && !val.isNotRewrite) {
                if (val.reviewValue) {
                  val.value = this.cloneFormData[val.reviewValue];
                } else {
                  val.value = this.cloneFormData[key];
                }
                if (val.type == "loadselect" && val.reviewLabel)
                  val.selectedLabel = this.cloneFormData[val.reviewLabel];
              }
            });
          });
        } else {
          this.cloneList.forEach((val) => {
            if (val.type == "loadselect") {
              val.selectedLabel = "";
            }
          });
        }
      }

      this.$forceUpdate();
    },
    uploadBackHandle(val) {
      this.$emit("upload-back", val);
      this.errorObj[val.id] = false;
    },
  },

  mounted() {
    this.initHandle();
  },
};
</script>

<style lang="scss" scoped>
::v-deep.el-radio {
  height: 32px;
  line-height: 32px;
}
::v-deep.el-input {
  input::-webkit-outer-spin-button,
  input::-webkit-inner-spin-button {
    -webkit-appearance: none;
  }
  input[type="number"] {
    -moz-appearance: textfield;
  }
}
.el-date-editor--datetimerange {
  width: auto;
}
.edit-list-wrap {
  display: flex;
  flex-wrap: wrap;
  overflow-y: scroll;
  overflow-x: hidden;
  margin-right: -12px;
  padding-right: 12px;
  .edit-list-left {
    position: relative;
    flex: 1;
    display: flex;
    flex-wrap: wrap;
    margin-right: -24px;
    width: 0;
  }
  .edit-list-right {
    height: 8px;
  }
  .edit-item-wrap {
    display: flex;
    align-items: center;
    padding-right: 24px;
    margin-bottom: 24px;
    .edit-label {
      flex-shrink: 0;
      // padding-left: 8px;
      .edit-text {
        position: relative;
        width: 100%;
        padding-right: 16px;
        text-align: right;
        // &::before {
        //   position: absolute;
        //   content: "*";
        //   color: #e34d59;
        //   top: 3px;
        //   left: -8px;
        // }
        span {
          font-size: 14px;
          color: rgba(#000, 0.9);
          font-weight: 400;
          font-size: 14px;
        }
        .star {
          display: inline-block;
          text-align: center;
          width: 8px;
          color: #e34d59;
          font-size: 12px;
        }
      }
    }
    .edit-item-right {
      position: relative;
      flex: 1;
      .check-box {
        display: flex;
        align-items: center;
        flex-wrap: wrap;
        margin-bottom: -16px;
        .check-item {
          display: flex;
          align-items: center;
          margin-right: 16px;
          margin-bottom: 16px;
          cursor: pointer;
          &:last-child {
            margin-right: 0;
          }
        }

        .check-icon {
          height: 16px;
          width: 16px;
          margin-right: 8px;
          border-radius: 3px;
          border: 1px solid #dcdcdc;
        }

        .check-icon.active {
          border: 1px solid $main-color;
          background-color: $main-color;
          background-image: url("~@/assets/icons/check_active_icon.png");
          background-size: contain;
        }
        .check-label {
          color: rgba(#000, 0.9);
          font-weight: 400;
          font-size: 14px;
          white-space: nowrap;
        }
      }
      .edit-error-label {
        opacity: 0;
        transition: opacity 0.3s;
        position: absolute;
        font-size: 12px;
        top: 110%;
        font-weight: 400;
        color: #e34d59;
        left: 8px;
      }
      &.errorStatus {
        .edit-error-label {
          opacity: 1;
        }
      }
    }
    &.flexStart {
      align-items: flex-start;
      .edit-label {
        padding-top: 4px;
      }
    }
    &.unNeed {
      .star {
        display: none !important;
      }
    }
    .table-edit-wrap {
      flex: 1;
      margin-top: 8px;
      .item-title {
        position: relative;
        padding-left: 10px;
        margin-bottom: 16px;
        .title-icon {
          position: absolute;
          left: 0;
          top: 4px;
          width: 4px;
          height: 12px;
          border-radius: 4px;
          background: linear-gradient(
            180deg,
            rgba(107, 114, 255, 1) 0%,
            rgba(34, 39, 209, 1) 100%
          );
        }
        .item-name {
          color: rgba(#000, 0.9);
          font-weight: 600;
          font-size: 14px;
        }
      }
    }
  }
}
</style>
